import re
import json
import logging
from typing import Dict, Tuple, Any

logger = logging.getLogger(__name__)

# 预编译正则表达式以提升性能
_QINXUS_PATTERN = re.compile(r'\.?\s*\{"qinxus":\s*"([^"]+)"\}')
_JSON_BLOCK_PATTERN = re.compile(r'```(?:json)?\s*({[\s\S]*?})\s*```')
_EMOTION_PATTERN = re.compile(r'"(joy|sadness|anger|fear|love)"\s*:\s*([0-9]*\.?[0-9]+)')

# 情感关键词集合，用于快速检查
_EMOTION_KEYWORDS = frozenset([
    "joy", "sadness", "anger", "love", "fear", "情感分析", "emotion analysis",
    "confusion", "trust", "anticipation", "gratitude", "pride"
])

def clean_response_text(text: str) -> str:
    """
    清理响应文本中的情感分析JSON部分和其他不需要的内容
    
    Args:
        text: 原始响应文本
        
    Returns:
        清理后的纯文本
    """
    try:
        if not text:
            return text
            
        # 快速路径：如果文本中没有花括号，直接返回
        if '{' not in text:
            return text
            
        # 首先检查明显的标记格式，如```json形式的代码块
        matches = _JSON_BLOCK_PATTERN.findall(text)
        if matches:
            logger.info(f"找到代码块中的JSON: {matches}")
            text = _JSON_BLOCK_PATTERN.sub('', text)
            
        # 检查文本中任何以 { 开始的可能JSON结构
        open_brace_positions = [m.start() for m in re.finditer(r'{', text)]
        for pos in reversed(open_brace_positions):  # 从后向前处理，避免位置偏移
            # 只处理出现在文本后60%部分的JSON
            if pos > len(text) * 0.4:
                # 提取可能的JSON部分进行检查
                possible_json = text[pos:]
                
                # 快速检查：使用集合交集来快速判断是否包含情感关键词
                possible_json_lower = possible_json.lower()
                if any(keyword in possible_json_lower for keyword in _EMOTION_KEYWORDS):
                    # 如果包含关键词，找到前一个换行符并截断文本
                    last_newline = text.rfind('\n', 0, pos)
                    if last_newline > 0:
                        logger.info(f"发现情感关键词，从位置 {last_newline} 截断")
                        return text[:last_newline].strip()
                    else:
                        logger.info(f"发现情感关键词，从位置 {pos} 截断")
                        return text[:pos].strip()
                
                # 尝试找到匹配的闭括号
                open_count = 1
                close_pos = pos + 1
                while close_pos < len(text) and open_count > 0:
                    if close_pos >= len(text):
                        break
                    if text[close_pos] == '{':
                        open_count += 1
                    elif text[close_pos] == '}':
                        open_count -= 1
                    close_pos += 1
                
                # 如果找到完整的JSON结构
                if open_count == 0 and close_pos <= len(text):
                    try:
                        json_str = text[pos:close_pos]
                        json_data = json.loads(json_str)
                        # 检查是否是情感分析数据
                        if any(key in json_data for key in ["joy", "sadness", "anger", "fear"]):
                            last_newline = text.rfind('\n', 0, pos)
                            if last_newline > 0:
                                logger.info(f"发现完整情感JSON，从位置 {last_newline} 截断")
                                return text[:last_newline].strip()
                            else:
                                logger.info(f"发现完整情感JSON，从位置 {pos} 截断")
                                return text[:pos].strip()
                    except json.JSONDecodeError:
                        # 如果无法解析，可能是不完整的JSON
                        # 使用预编译的正则表达式检查
                        if _EMOTION_PATTERN.search(json_str):
                            last_newline = text.rfind('\n', 0, pos)
                            if last_newline > 0:
                                logger.info(f"发现不完整情感JSON模式，从位置 {last_newline} 截断")
                                return text[:last_newline].strip()
                            else:
                                logger.info(f"发现不完整情感JSON模式，从位置 {pos} 截断")
                                return text[:pos].strip()
        
        # 检查特殊情况：可能的不完整JSON结构(末尾有 { 但没有完整的 })
        if '{' in text[-50:]:
            last_brace = text.rfind('{')
            if last_brace > len(text) * 0.5:  # 在后半部分
                if _EMOTION_PATTERN.search(text[last_brace:]):
                    logger.info(f"发现文本末尾不完整JSON，从位置 {last_brace} 截断")
                    return text[:last_brace].strip()
        
        # 删除包含情感分析关键词的尾部文本
        text_lower = text.lower()
        for keyword in _EMOTION_KEYWORDS:
            if keyword in text_lower:
                pos = text_lower.rfind(keyword)
                if pos > len(text) * 0.5:  # 在后半部分
                    # 查找关键词所在行的开始位置
                    line_start = text.rfind('\n', 0, pos)
                    if line_start > 0:
                        logger.info(f"找到情感关键词 '{keyword}'，从位置 {line_start} 截断")
                        return text[:line_start].strip()
        
        return text
    except Exception as e:
        logger.error(f"清理响应文本时出错: {str(e)}")
        return text


def extract_qinxus_emotion(text: str) -> Tuple[str, str]:
    """
    高性能版本：从文本中提取qinxus格式的情绪信息
    
    Args:
        text: 包含情绪标识的文本
        
    Returns:
        Tuple[str, str]: (纯文本, 情绪)
    """
    try:
        # 快速路径检查：如果文本中没有qinxus关键字，直接返回
        if 'qinxus' not in text:
            return text, "neutral"
        
        # 使用预编译的正则表达式进行匹配
        match = _QINXUS_PATTERN.search(text)
        
        if match:
            emotion = match.group(1)
            # 使用字符串切片而不是正则替换来提高性能
            match_start, match_end = match.span()
            clean_text = (text[:match_start] + text[match_end:]).strip()
            
            # 只在调试模式下记录日志
            if logger.isEnabledFor(logging.INFO):
                logger.info(f"提取到qinxus情绪: {emotion}, 纯文本长度: {len(clean_text)}")
            return clean_text, emotion
        else:
            # 如果没找到情绪标识，返回原文本和默认情绪
            if logger.isEnabledFor(logging.WARNING):
                logger.warning("未找到qinxus格式的情绪标识，使用默认情绪neutral")
            return text, "neutral"
            
    except Exception as e:
        logger.error(f"提取qinxus情绪时出错: {str(e)}")
        return text, "neutral"


def is_possible_json_fragment(text: str) -> bool:
    """
    高性能版本：检查文本是否可能是JSON片段的一部分
    
    Args:
        text: 要检查的文本
        
    Returns:
        bool: 是否可能是JSON片段
    """
    # 快速路径：如果没有花括号，不可能是JSON
    if '{' not in text and '}' not in text:
        return False
        
    # 检查是否包含花括号但不匹配
    open_braces = text.count('{')
    close_braces = text.count('}')
    
    # 如果存在花括号但不平衡，可能是JSON片段
    if (open_braces > 0 or close_braces > 0) and open_braces != close_braces:
        # 进一步检查是否包含情感关键词
        text_lower = text.lower()
        return any(keyword in text_lower for keyword in _EMOTION_KEYWORDS)
                        
    return False


def fix_common_json_errors(json_str: str) -> str:
    """
    修复常见的JSON错误
    
    Args:
        json_str: 可能有错误的JSON字符串
        
    Returns:
        修复后的JSON字符串
    """
    # 修复缺少逗号
    json_str = re.sub(r'(\d+|\btrue\b|\bfalse\b|\bnull\b|"[^"]*")\s*\n\s*"', r'\1,\n"', json_str)
    # 修复多余的逗号
    json_str = re.sub(r',\s*}', r'}', json_str)
    # 确保所有的键值对都有引号
    json_str = re.sub(r'([{,]\s*)([a-zA-Z0-9_]+)(\s*:)', r'\1"\2"\3', json_str)
    return json_str


def extract_emotions_manually(text: str) -> Dict[str, float]:
    """
    当JSON解析失败时，尝试手动提取情感值
    
    Args:
        text: 包含情感信息的文本
        
    Returns:
        情感值字典
    """
    result = get_default_emotions()
    
    # 定义情感关键词和正则表达式
    patterns = {
        "joy": r"(?:joy)\"?\s*:\s*([0-9]*\.?[0-9]+)",
        "sadness": r"(?:sadness)\"?\s*:\s*([0-9]*\.?[0-9]+)",
        "anger": r"(?:anger)\"?\s*:\s*([0-9]*\.?[0-9]+)", 
        "fear": r"(?:fear)\"?\s*:\s*([0-9]*\.?[0-9]+)",
        "love": r"(?:love)\"?\s*:\s*([0-9]*\.?[0-9]+)",
        "confusion": r"(?:confusion)\"?\s*:\s*([0-9]*\.?[0-9]+)",
        "trust": r"(?:trust)\"?\s*:\s*([0-9]*\.?[0-9]+)",
        "anticipation": r"(?:anticipation)\"?\s*:\s*([0-9]*\.?[0-9]+)",
        "gratitude": r"(?:gratitude)\"?\s*:\s*([0-9]*\.?[0-9]+)",
        "pride": r"(?:pride)\"?\s*:\s*([0-9]*\.?[0-9]+)"
    }
    
    # 尝试提取每种情感
    for emotion, pattern in patterns.items():
        matches = re.search(pattern, text)
        if matches:
            try:
                value = float(matches.group(1))
                result[emotion] = max(0.0, min(1.0, value))  # 确保值在0-1范围内
            except (ValueError, IndexError):
                pass
    
    return result


def normalize_emotions(scores: Dict[str, Any]) -> Dict[str, float]:
    """
    规范化情感分数，确保都在0-1范围内
    
    Args:
        scores: 原始情感分数字典
        
    Returns:
        规范化后的情感分数字典
    """
    normalized = {}
    for emotion in ["joy", "sadness", "anger", "fear", "love", 
                    "confusion", "trust", "anticipation", "gratitude", "pride"]:
        score = scores.get(emotion, 0.0)
        normalized[emotion] = max(0.0, min(1.0, float(score)))
    return normalized


def get_default_emotions() -> Dict[str, float]:
    """
    获取默认的情感分数
    
    Returns:
        默认情感分数字典
    """
    return {
        "joy": 0.0,
        "sadness": 0.0,
        "anger": 0.0,
        "fear": 0.0,
        "love": 0.0,
        "confusion": 0.0,
        "trust": 0.0,
        "anticipation": 0.0,
        "gratitude": 0.0,
        "pride": 0.0
    }


def get_default_basic_emotions() -> Dict[str, float]:
    """
    获取默认的五种基本情绪值
    
    Returns:
        默认的五种基本情绪值字典
    """
    return {
        "happy": 0.0,
        "neutral": 1.0,
        "sad": 0.0,
        "angry": 0.0,
        "fearful": 0.0
    }


def convert_to_basic_emotions(emotions: Dict[str, float]) -> Dict[str, float]:
    """
    将复杂情感转换为五种基本情绪
    
    Args:
        emotions: 复杂情感字典
        
    Returns:
        五种基本情绪字典
    """
    basic_emotions = {
        "happy": emotions.get("joy", 0.0),
        "neutral": max(0.0, 1.0 - sum([
            emotions.get("joy", 0.0),
            emotions.get("sadness", 0.0),
            emotions.get("anger", 0.0),
            emotions.get("fear", 0.0)
        ])),
        "sad": emotions.get("sadness", 0.0),
        "angry": emotions.get("anger", 0.0),
        "fearful": emotions.get("fear", 0.0)
    }
    
    # 归一化处理，确保总和为1
    total = sum(basic_emotions.values())
    if total > 0:
        for key in basic_emotions:
            basic_emotions[key] = basic_emotions[key] / total
    
    return basic_emotions 